package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.common.Constants;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.util.JsonUtils;
import com.heima.feign.ArticleFeign;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.WmNewsDownOrUpMsgDTO;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.search.pojo.ArticleDoc;
import com.heima.search.service.ApSearchHistroyService;
import com.heima.search.service.ApUserSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.heima.common.Constants.INDEX_NAME;

@Slf4j
@Service
public class ApUserSearchServiceImpl implements ApUserSearchService {


    @Autowired
    RestHighLevelClient client;

    @Autowired
    private ApSearchHistroyService histroyService;

    @Autowired
    private ArticleFeign articleFeign;

    @Override
    public void onArticleDownOrUp(WmNewsDownOrUpMsgDTO wmNewsDownOrUpMsgDTO) {
        Long articleId = wmNewsDownOrUpMsgDTO.getArticleId();
        Boolean enable = wmNewsDownOrUpMsgDTO.getEnable();
        if(enable){
            // 如果是上架 添加到ES
            onArticleCreate(articleId);
        }else{
            // 如果是下架 从ES删除
            DeleteRequest deleteRequest = new DeleteRequest(INDEX_NAME).id(""+articleId);
            try {
                DeleteResponse delete = client.delete(deleteRequest, RequestOptions.DEFAULT);
                log.info("删除文档结果：{}", delete.getResult());
            } catch (IOException e) {
                log.error("删除ES异常：{}", ExceptionUtils.getStackTrace(e));
            }
        }
    }

    @Override
    public void onArticleCreate(long articleId) {
        //  根据articleId插叙article数据，feign
        ArticleDto dto = articleFeign.findById(articleId);
        if(dto == null){
            log.error("根据articleId查询article为空:{}", articleId);
            return;
        }
        //  导入ES
        IndexRequest request = new IndexRequest(INDEX_NAME).id(""+articleId);
        ArticleDoc doc = new ArticleDoc(dto);
        request.source(JSON.toJSONString(doc), XContentType.JSON);
        try {
            IndexResponse response = client.index(request, RequestOptions.DEFAULT);
            DocWriteResponse.Result result = response.getResult();
            log.info("添加文档结果：{}", result.getLowercase());
        } catch (IOException e) {
            log.error("添加文档异常, id:{}，异常：{}", articleId, ExceptionUtils.getStackTrace(e));
        }
    }

    @Override
    public List<ArticleDoc> search(UserSearchDto dto) {
        SearchRequest searchRequest  = new SearchRequest(INDEX_NAME);
        // 搜索条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 搜索的关进此必须要满足，并且要算分
        boolQueryBuilder.must(QueryBuilders.multiMatchQuery(dto.getSearchWords(), "title", "content"));
        if(dto.getMinBehotTime() != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime()));
        }
        // bool查询
        searchRequest.source().query(boolQueryBuilder);
        // 分页
        searchRequest.source().from(0);
        searchRequest.source().size(dto.getPageSize());
        // 排序
        searchRequest.source().sort("publishTime", SortOrder.DESC);
        // 高亮
        HighlightBuilder highlighter = new HighlightBuilder();
        highlighter.preTags("<font color='red'>");
        highlighter.postTags("</font>");
        highlighter.field("title");
        // 如果查询字段和高亮字段不匹配
        highlighter.requireFieldMatch(false);
        searchRequest.source().highlighter(highlighter);
        // 返回除了content之外的所有字段,因为搜索列表中并不需要content
        searchRequest.source().fetchSource(null, "content");
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = searchResponse.getHits();
            List<ArticleDoc> resultList = new ArrayList<>();
            for(SearchHit hit : hits.getHits()){
                String json = hit.getSourceAsString();
                ArticleDoc articleDoc = JsonUtils.toBean(json, ArticleDoc.class);
                // 获取高亮
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                if(!CollectionUtils.isEmpty(highlightFields)){
                    HighlightField highlightField = highlightFields.get("title");
                    if(highlightField != null){
                        Text[] fragments = highlightField.getFragments();
                        if(fragments != null && fragments.length > 0 && fragments[0] != null) {
                            articleDoc.setTitle(fragments[0].toString());
                        }
                    }
                }
                resultList.add(articleDoc);
            }
            // 保存搜素的历史记录
            histroyService.saveHistory(dto.getSearchWords(), dto.getEquipmentId());
            return resultList;
        }catch(Exception e){
            log.error("搜索异常：{}", ExceptionUtils.getStackTrace(e));
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    @Override
    public void importArticle(List<ArticleDto> articleDtoList) {
        // 批量请求
        BulkRequest bulkRequest = new BulkRequest();
        for(ArticleDto dto : articleDtoList){
            if(!StringUtils.isEmpty(dto.getStaticUrl())){
                // insert or update doc的请求
                IndexRequest indexRequest = new IndexRequest(INDEX_NAME).id(""+dto.getId());
                indexRequest.source(JSON.toJSONString(new ArticleDoc(dto)), XContentType.JSON);
                bulkRequest.add(indexRequest);
            }
        }
        if(bulkRequest.numberOfActions() <= 0){
            return;
        }
        try{
            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            if(bulkResponse.hasFailures()){
                log.info("异常信息：{}", bulkResponse.buildFailureMessage());
            }
        }catch(Exception e){
            log.error("数据导入ES异常：{}", ExceptionUtils.getStackTrace(e));
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }
}
